package com.xhwl.logistics.service.feign.impl;


import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xhwl.common.dto.cent.vehicle.feign.VehicleAccessRecordRealtimeQuery;
import com.xhwl.common.dto.cent.vehicle.feign.VehicleCarTotalTwoAreaDTO;
import com.xhwl.common.dto.cent.vehicle.feign.VehicleVisitorCarDTO;
import com.xhwl.common.dto.cent.vehicle.feign.VehicleVisitorCarQuery;
import com.xhwl.common.dto.cent.visitor.VisitorInfoDTO;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.Project;
import com.xhwl.common.pojo.cent.visitor.Follower;
import com.xhwl.common.query.cent.sdata.ProjectQuery;
import com.xhwl.common.query.cent.vehicle.VehcParkingLotQuery;
import com.xhwl.common.utils.ChkUtil;
import com.xhwl.logistics.bo.cent.VehicleIntegratedConfigBO;
import com.xhwl.logistics.dao.mapper.IVehicleAccessRecordMapper;
import com.xhwl.logistics.dto.http.ParkingLotAreaInfoDaHuaDTO;
import com.xhwl.logistics.entity.VehicleAccessRecord;
import com.xhwl.logistics.entity.VehicleArea;
import com.xhwl.logistics.entity.VehicleCar;
import com.xhwl.logistics.service.cent.IProjectService;
import com.xhwl.logistics.service.cent.QueryDeviceService;
import com.xhwl.logistics.service.feign.IVehicleCarAndAccessRecordFeignService;
import com.xhwl.logistics.service.impl.VehicleAccessRecordServiceImpl;
import com.xhwl.logistics.service.impl.VehicleAreaServiceImpl;
import com.xhwl.logistics.service.impl.VehicleCarServiceImpl;
import com.xhwl.logistics.service.impl.http.DaHuaHttpServiceImpl;
import com.xhwl.logistics.service.impl.http.HongMenHttpServiceImpl;
import com.xhwl.logistics.util.UploadUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestPart;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 提供车辆和出行记录的feign接口的实现类
 */
@Slf4j
//@Service
public class VehicleCarAndAccessRecordFeignServiceImpl implements IVehicleCarAndAccessRecordFeignService {

    @Autowired
    private VehicleAccessRecordServiceImpl vehicleAccessRecordService;

    @Autowired
    private QueryDeviceService queryDeviceService;

    @Autowired
    private VehicleCarServiceImpl vehicleCarService;

    @Autowired
    private IVehicleAccessRecordMapper vehicleAccessRecordMapper;

    @Resource
    private VehicleAreaServiceImpl vehicleAreaService;

    @Resource
    private DaHuaHttpServiceImpl daHuaHttpService;

    @Resource
    private HongMenHttpServiceImpl hongMenHttpService;

    @Autowired
    private IProjectService iProjectService;


    /**
     * 常量
     */
    private static final String allArea = "1";
    private static final String insideArea = "2";
    private static final String outsideArea = "3";

    /**
     * 根据项目id和时间获取集成配置指定的区域信息的进记录减去出记录的实现类
     */
    @Override
    public VehicleCarTotalTwoAreaDTO getTwoAreaCarInfo(VehicleAccessRecordRealtimeQuery vehicleAccessRecordRealtimeQuery) {
        VehicleCarTotalTwoAreaDTO vehicleCarTotalTwoAreaDTO = new VehicleCarTotalTwoAreaDTO();
        if(vehicleAccessRecordRealtimeQuery != null){
            if(vehicleAccessRecordRealtimeQuery.getProjectId() == null){
                throw new BusinessException("项目id为空！");
            }
            VehicleIntegratedConfigBO vehicleIntegratedConfigBO = queryDeviceService.queryIntegratedConfigFromProjectId(vehicleAccessRecordRealtimeQuery.getProjectId());
            if(vehicleAccessRecordRealtimeQuery.getStartTime() == null ||vehicleAccessRecordRealtimeQuery.getEndTime() == null){
                throw new BusinessException("统计时间段有空值，无法统计！");
            }
            //园区全部
            if(vehicleAccessRecordRealtimeQuery.getParkingLotName() == null ||
                    StringUtils.equals(vehicleAccessRecordRealtimeQuery.getParkingLotName(), allArea)){

                List<VehicleAccessRecord> vehicleAccessRecordListInA = vehicleAccessRecordService.list(conditionForCarInFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark(), null, true));
                List<VehicleAccessRecord> vehicleAccessRecordListInB = vehicleAccessRecordService.list(conditionForCarInFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemarkUnion(), null, true));

                List<VehicleAccessRecord> vehicleAccessRecordListOutA = vehicleAccessRecordService.list(conditionForCarOutFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark(), null, true));
                List<VehicleAccessRecord> vehicleAccessRecordListOutB = vehicleAccessRecordService.list(conditionForCarOutFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemarkUnion(), null, true));

                vehicleCarTotalTwoAreaDTO.setAreACarCount(vehicleAccessRecordListInA.size() - vehicleAccessRecordListOutA.size());
                vehicleCarTotalTwoAreaDTO.setAreACarIn(vehicleAccessRecordListInA.size());
                vehicleCarTotalTwoAreaDTO.setAreACarOut(vehicleAccessRecordListOutA.size());
                vehicleCarTotalTwoAreaDTO.setAreBCarCount(vehicleAccessRecordListInB.size() - vehicleAccessRecordListOutB.size());
                vehicleCarTotalTwoAreaDTO.setAreBCarIn(vehicleAccessRecordListInB.size());
                vehicleCarTotalTwoAreaDTO.setAreBCarOut(vehicleAccessRecordListOutB.size());
            }
            //园区内部人员
            else if(StringUtils.equals(vehicleAccessRecordRealtimeQuery.getParkingLotName(), insideArea)){
                List<VehicleCar> vehicleCarList = vehicleCarService.list(conditionForCarFromProjectId(vehicleAccessRecordRealtimeQuery.getProjectId()));
                List<String> plateNumbers = vehicleCarList.stream().map(VehicleCar::getPlateNumber).collect(Collectors.toList());

                List<VehicleAccessRecord> vehicleAccessRecordListInA = vehicleAccessRecordService.list(conditionForCarInFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark(), plateNumbers, true));

                List<VehicleAccessRecord> vehicleAccessRecordListOutA = vehicleAccessRecordService.list(conditionForCarOutFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark(), plateNumbers,true));

                vehicleCarTotalTwoAreaDTO.setAreACarCount(vehicleAccessRecordListInA.size() - vehicleAccessRecordListOutA.size());
                vehicleCarTotalTwoAreaDTO.setAreACarIn(vehicleAccessRecordListInA.size());
                vehicleCarTotalTwoAreaDTO.setAreACarOut(vehicleAccessRecordListOutA.size());
            }
            //非园区人员
            else if(StringUtils.equals(vehicleAccessRecordRealtimeQuery.getParkingLotName(), outsideArea)){
                List<VehicleCar> vehicleCarList = vehicleCarService.list(conditionForCarFromProjectId(vehicleAccessRecordRealtimeQuery.getProjectId()));
                List<String> plateNumbers = vehicleCarList.stream().map(VehicleCar::getPlateNumber).collect(Collectors.toList());

                List<VehicleAccessRecord> vehicleAccessRecordListInA = vehicleAccessRecordService.list(conditionForCarInFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark(), plateNumbers, false));
                List<VehicleAccessRecord> vehicleAccessRecordListInB = vehicleAccessRecordService.list(conditionForCarInFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemarkUnion(), plateNumbers, false));

                List<VehicleAccessRecord> vehicleAccessRecordListOutA = vehicleAccessRecordService.list(conditionForCarOutFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark(), plateNumbers,false));
                List<VehicleAccessRecord> vehicleAccessRecordListOutB = vehicleAccessRecordService.list(conditionForCarOutFromTimeAndArea(vehicleAccessRecordRealtimeQuery.getProjectId(),
                        vehicleAccessRecordRealtimeQuery.getStartTime(), vehicleAccessRecordRealtimeQuery.getEndTime(),
                        vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemarkUnion(), plateNumbers,false));

                vehicleCarTotalTwoAreaDTO.setAreACarCount(vehicleAccessRecordListInA.size() - vehicleAccessRecordListOutA.size());
                vehicleCarTotalTwoAreaDTO.setAreACarIn(vehicleAccessRecordListInA.size());
                vehicleCarTotalTwoAreaDTO.setAreACarOut(vehicleAccessRecordListOutA.size());
                vehicleCarTotalTwoAreaDTO.setAreBCarCount(vehicleAccessRecordListInB.size() - vehicleAccessRecordListOutB.size());
                vehicleCarTotalTwoAreaDTO.setAreBCarIn(vehicleAccessRecordListInB.size());
                vehicleCarTotalTwoAreaDTO.setAreBCarOut(vehicleAccessRecordListOutB.size());
            }
        }
        return vehicleCarTotalTwoAreaDTO;
    }

    /**
     * 根据项目id查询车辆信息
     */
    private Wrapper<VehicleCar> conditionForCarFromProjectId(Integer projectId){
        return new LambdaQueryWrapper<VehicleCar>()
                .eq(VehicleCar::getProjectId, projectId);
    }

    /**
     * 根据时间段和区域字段来获取某个区域在该时间段的进记录
     * @param projectId
     * @param startTime
     * @param endTime
     * @param remark
     * @param plateNumbers
     * @param need：true：表示车牌号在plateNumbers中，false：表示车牌号不在plateNumbers中
     * @return
     */
    private Wrapper<VehicleAccessRecord> conditionForCarInFromTimeAndArea(Integer projectId, Date startTime, Date endTime, String remark, List<String> plateNumbers, boolean need){
        LambdaQueryWrapper<VehicleAccessRecord> vehicleAccessRecordLambdaQueryWrapper = new LambdaQueryWrapper<VehicleAccessRecord>()
                .eq(VehicleAccessRecord::getProjectId, projectId)
                .eq(Objects.nonNull(remark), VehicleAccessRecord::getParkId, remark)
                .ge(VehicleAccessRecord::getEnterTime, startTime)
                .lt(VehicleAccessRecord::getEnterTime, endTime);
        if(need){
            return vehicleAccessRecordLambdaQueryWrapper.in(Objects.nonNull(plateNumbers), VehicleAccessRecord::getPlateNumber, plateNumbers);
        }else{
            return vehicleAccessRecordLambdaQueryWrapper.notIn(Objects.nonNull(plateNumbers), VehicleAccessRecord::getPlateNumber, plateNumbers);
        }
    }

    /**
     * 根据时间段和区域字段来获取某个区域在该时间段的出记录
     */
    private Wrapper<VehicleAccessRecord> conditionForCarOutFromTimeAndArea(Integer projectId, Date startTime, Date endTime, String remark, List<String> plateNumbers, boolean need){
        LambdaQueryWrapper<VehicleAccessRecord> vehicleAccessRecordLambdaQueryWrapper = new LambdaQueryWrapper<VehicleAccessRecord>()
                .eq(VehicleAccessRecord::getProjectId, projectId)
                .eq(Objects.nonNull(remark), VehicleAccessRecord::getParkId, remark)
                .ge(VehicleAccessRecord::getExitTime, startTime)
                .lt(VehicleAccessRecord::getExitTime, endTime);
        if (need){
            return vehicleAccessRecordLambdaQueryWrapper.in(Objects.nonNull(plateNumbers), VehicleAccessRecord::getPlateNumber, plateNumbers);
        }else {
            return vehicleAccessRecordLambdaQueryWrapper.notIn(Objects.nonNull(plateNumbers), VehicleAccessRecord::getPlateNumber, plateNumbers);
        }
    }

    @Override
    public List<VehicleVisitorCarDTO> accessRecordFeignList(@RequestPart("visitorCarQuery") VehicleVisitorCarQuery visitorCarQuery){
        List<VehicleVisitorCarDTO> records =   vehicleAccessRecordMapper.getVisitorCarRecordList(visitorCarQuery);
        if (CollectionUtils.isEmpty(records)){
            return new ArrayList<>();
        }
        return records;
    }

    @Override
    public VisitorInfoDTO handleFaceUrl(VisitorInfoDTO info){
        UploadUtils utils = new UploadUtils();
        // 处理访客人员人脸信息
        if (StringUtils.isNotBlank(info.getFaceUrl())){
            String faceUrlBase64 = info.getFaceUrl().replaceAll("[\\s*\t\n\r]", "");
            faceUrlBase64 = utils.uploadImgBase64(faceUrlBase64);
            info.setFaceUrl(faceUrlBase64);
        }
        // 处理随访人员人脸信息
        List<Follower> followerList = info.getFollowerList();
        if (!CollectionUtils.isEmpty(followerList)){
            followerList.forEach(item ->{
                if (StringUtils.isNotBlank(item.getFaceUrl())){
                    String followerFaceBase64 = item.getFaceUrl().replaceAll("[\\s*\t\n\r]", "");
                    followerFaceBase64 = utils.uploadImgBase64(followerFaceBase64);
                    item.setFaceUrl(followerFaceBase64);
                }
            });
        }
        return info;
    }

    @Override
    public ResultJson queryAccessRecordToday(VehcParkingLotQuery query) {
        if(query.getProjectId() == null && query.getEnterpriseId() == null) {
            throw new BusinessException("项目ID和企业ID不能都为空");
        }
        List<Integer> projectIds = new ArrayList<>();
        if(ChkUtil.isNotNull(query.getProjectId())) {
            projectIds.add(query.getProjectId());
        }
        if(ChkUtil.isNotNull(query.getEnterpriseId())) {
            // 用企业ID查询出该企业下所有的项目ID
            ProjectQuery projectQuery = new ProjectQuery();
            projectQuery.setEnterpriseIds(Arrays.asList(query.getEnterpriseId()));
            List<Project> projectList = iProjectService.list(projectQuery, null);
            if(ChkUtil.isNotNull(projectList)) {
                projectIds.addAll(projectList.stream().map(Project::getId).collect(Collectors.toList()));
            }
        }
        if(ChkUtil.isNull(projectIds)) {
            return ResultJson.success();
        }
        Date today = DateUtil.beginOfDay(new Date());
        LambdaQueryWrapper<VehicleAccessRecord> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper
                .ge(VehicleAccessRecord::getEnterTime, today)
                .in(VehicleAccessRecord::getProjectId, projectIds);
        int inCount = vehicleAccessRecordService.count(lambdaQueryWrapper);
        Map<String, Object> map = new HashMap<>();
        map.put("inCount", inCount);
        return ResultJson.success(map);
    }

    @Override
    public Integer getCarportNumberByType(Integer projectId, Integer type){
        if (ObjectUtils.isEmpty(projectId)) {
            throw new BusinessException("项目id不能为空");
        }
        Integer total = 0;
        VehicleIntegratedConfigBO vehicleIntegratedConfigBO = queryDeviceService.queryIntegratedConfigFromProjectId(projectId);
        if (type == 1){
            // 大华生活区车位
            List<VehicleArea> vehicleAreaList = vehicleAreaService.list(new LambdaQueryWrapper<VehicleArea>()
                    .eq(VehicleArea::getRemark, vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getRemark()));
            if (CollectionUtils.isEmpty(vehicleAreaList)){
                log.error("通过该区域备注未找到区域信息！");
                return total;
            }
            if (vehicleAreaList.size() > 1){
                log.error("通过该区域备注找到多个区域信息！");
                return total;
            }
            List<ParkingLotAreaInfoDaHuaDTO> parkingLotAreaInfo = daHuaHttpService.getParkingLotAreaInfo(vehicleIntegratedConfigBO);
            ParkingLotAreaInfoDaHuaDTO parkingLotAreaInfoDaHuaDTO = parkingLotAreaInfo.stream()
                    .filter(s -> StringUtils.equals(s.getId(), vehicleAreaList.get(0).getThirdAreaId()))
                    .findAny()
                    .orElse(null);
            if (Objects.isNull(parkingLotAreaInfoDaHuaDTO)) {
                log.error("大华将该区域删除，请同步最新区域！");
                return total;
            }
            return parkingLotAreaInfoDaHuaDTO.getTotalLot();
        }
        if (type == 2){
            // 红门办公区域车位
            String customParams = vehicleIntegratedConfigBO.getVehicleParkingInfoBO().getCustomParams();
            if (StringUtils.isBlank(customParams)){
                log.error("自定义参数为空");
                return total;
            }
            JSONObject customParamsObj = JSON.parseObject(customParams);
            if (!customParamsObj.getBoolean("doubleFunContrMn")){
                log.error("未开启双厂商配置");
                return total;
            }
            String host = customParamsObj.getString("host");
            JSONObject object = hongMenHttpService.queryParkingLot(host);
            return object.getInteger("parking_total");
        }
        return total;
    }
}
